<?php

namespace App\Trip\Train\Seat;

use App\Trip\Train\Seat\Interfaces\SeatsInterface;
use App\Trip\Train\TrainType;
use Exception;
use Illuminate\Support\Facades\Validator;

class Seats implements SeatsInterface
{
    const REQUIRED_FIELDS
        = [
            "train_code"        => "required",
            "seat_name"         => "required",
            "seat_price"        => "required",
            "from_station_code" => "required",
            "to_station_code"   => "required",
        ];

    /**
     * 坐席类型 1 座位 2 铺席
     *
     * @const int SEAT_TYPE_SEAT 坐席
     * @const int SEAT_TYPE_BED 铺席
     */
    const  SEAT_TYPE_SEAT = 1;
    const  SEAT_TYPE_BED  = 2;
    /**
     * @const int LOWER_BED 下铺
     * @const int MIDDLE_BED 中铺
     * @const int  UPPER_BED 上铺
     */
    const  UPPER_BED  = 3;
    const  MIDDLE_BED = 2;
    const  LOWER_BED  = 1;

    /**
     * 定义 火车票 铺席
     */
    const TRAIN_BEDS
        = [
            self::LOWER_BED  => '下铺',
            self::MIDDLE_BED => '中铺',
            self::UPPER_BED  => '上铺',
        ];
    /**
     * 坐席类型 1 座位 2 铺席
     */
    const SEAT_TYPE
        = [
            "无座"   => self::SEAT_TYPE_SEAT,
            "硬座"   => self::SEAT_TYPE_SEAT,
            "二等座" => self::SEAT_TYPE_SEAT,
            "一等座" => self::SEAT_TYPE_SEAT,
            "商务座" => self::SEAT_TYPE_SEAT,
            "特等座" => self::SEAT_TYPE_SEAT,
            "硬卧"   => self::SEAT_TYPE_BED,
            "软卧"   => self::SEAT_TYPE_BED,
        ];

    /**
     * 座位和类型的映射
     */
    const SEAT_MAP_TO_TYPE
        = [
            "A"    => self::SEAT_TYPE_SEAT,
            "B"    => self::SEAT_TYPE_SEAT,
            "C"    => self::SEAT_TYPE_SEAT,
            "D"    => self::SEAT_TYPE_SEAT,
            "E"    => self::SEAT_TYPE_SEAT,
            "F"    => self::SEAT_TYPE_SEAT,
            "1"    => self::SEAT_TYPE_BED,
            "2"    => self::SEAT_TYPE_BED,
            "3"    => self::SEAT_TYPE_BED,
            "下铺" => self::SEAT_TYPE_BED,
            "中铺" => self::SEAT_TYPE_BED,
            "上铺" => self::SEAT_TYPE_BED,
        ];

    const   SEAT_SIDES
        = [
            "窗", "过道",
        ];
    private string $train_code;
    /**
     *   席别:商务座,特等座,一等座,二等座,二等包座,高级软卧,
     *   软卧,一等卧,动卧,
     *   一等包座,高级动卧,包厢硬卧,一人软包,观光座,硬卧,二等卧,软座,硬座,无座,其它",
     *   seat_inventory -1 标识未设置库存
     */
    private string $seat_name;
    private string $seat_name_uy;
    private float  $seat_price;
    private int    $seat_inventory    = -1;
    private array  $details;
    private string $alias_name;
    private string $to_station_code   = '';
    private string $from_station_code = '';

    /**
     * @throws Exception
     */
    public function __construct(array $seatData)
    {
        $validator = Validator::make($seatData, self::REQUIRED_FIELDS);
        if ($validator->fails()) {
            throw new Exception("参数错误");
        }

        $this->details = [];
        $this->setTrainCode($seatData['train_code']);
        $this->setFromStationCode($seatData['from_station_code']);
        $this->setToStationCode($seatData['to_station_code']);
        $this->setPrice($seatData['seat_price']);
        $this->setName($seatData['seat_name']);
        $this->setInventory($seatData['seat_inventory'] ?? -1);
        $this->setAliasName($seatData['alias_name'] ?? '');
        $this->saveTripInventory();
    }

    protected function setPrice($seat_price)
    {
        $this->seat_price = $seat_price;
    }

    protected function setName($seat_name)
    {
        $this->seat_name    = $seat_name;
        $this->seat_name_uy = SeatName::trans($seat_name, 'uy');
    }

    /**
     * @inheritDoc
     */
    protected function setInventory($seat_inventory)
    {
        $this->seat_inventory = $seat_inventory;
    }

    public function saveTripInventory(): bool
    {
        if ($this->seat_inventory >= 0 && $this->from_station_code && $this->to_station_code) {
            $seatInventory = new SeatInventory($this->getTrainCode(), $this->from_station_code, $this->to_station_code, $this->seat_name);
            $seatInventory->setInventory($this->seat_inventory);
        }
        return true;
    }

    public function getTrainCode(): string
    {
        return $this->train_code;
    }

    // 设置别名 比如无座 对应的别名可能是  硬座

    protected function setTrainCode(string $train_code)
    {
        $this->train_code = $train_code;
    }

    public function addDetail(SeatInfo $detail)
    {
        $this->details[] = [
            'name'    => $detail->getName(),
            'price'   => $detail->getPrice(),
            'name_uy' => $detail->getNameUy(),
        ];
    }

    public function getName(): string
    {
        return $this->seat_name;
    }

    public function getPrice(): float
    {
        return $this->seat_price;

    }

    public function getNameUy(): string
    {
        return $this->seat_name_uy;
    }

    public function __toString()
    {
        return json_encode($this->toArray(), JSON_UNESCAPED_UNICODE);
    }

    public function toArray(): array
    {
        return [
            "train_code"        => $this->getTrainCode(),
            "from_station_code" => $this->getFromStationCode(),
            "to_station_code"   => $this->getToStationCode(),
            "type_name"         => $this->getAliasName(),
            "seat_name"         => $this->getName(),
            "seat_name_uy"      => $this->getNameUy(),
            "seat_price"        => $this->getPrice(),
            "details"           => $this->seatDetails(),
            "select_seats"      => $this->canSelectSeats(),
            "seat_type"         => $this->getSeatType(),
        ];
    }

    public function getFromStationCode(): string
    {
        return $this->from_station_code;
    }

    protected function setFromStationCode(string $from_station_code)
    {
        $this->from_station_code = $from_station_code;
    }

    public function getToStationCode(): string
    {
        return $this->to_station_code;
    }

    protected function setToStationCode(string $to_station_code)
    {
        $this->to_station_code = $to_station_code;
    }

    public function getAliasName(): string
    {
        return $this->alias_name;
    }

    protected function setAliasName(string $alias_name = '')
    {
        $this->alias_name = $alias_name;
    }

    public function seatDetails(): array
    {
        return $this->details;
    }

    // 获取车次座位可选的坐席|铺席列表

    /**
     * 座席的可选座位 及价格
     *
     * @return array
     */
    public function canSelectSeats(): array
    {
        $seats = $this->getTrainSeatSeats();
        return collect($seats)
            ->map(function ($seat) {
                $seat['service_fee'] = SeatType::selectFee($this->getSeatType());
                return $seat;
            })
            ->toArray();
    }

    /**
     * 获取坐席的座位
     *
     * @return array
     */
    private function getTrainSeatSeats(): array
    {
        if ($this->seat_name == '无座') {
            return [];
        }
        $train_type   = TrainType::getTrainType($this->train_code);
        $select_seats = config('trip.train.select_seats');
        if (!isset($select_seats[$train_type])) {
            return [];
        }
        $type_seats = $select_seats[$train_type];
        return $type_seats[$this->seat_name] ?? [];
    }

    /**
     * @return int
     */
    public function getSeatType(): int
    {
        return self::SEAT_TYPE[$this->seat_name] ?? 0;
    }

    public function toAddData(): array
    {
        return [
            "train_code" => $this->getTrainCode(),
            "from_code"  => $this->getFromStationCode(),
            "to_code"    => $this->getToStationCode(),
            "type_name"  => $this->getAliasName(),
            "seat_name"  => $this->getName(),
            "seat_price" => $this->getPrice(),
        ];
    }

    public function getShowSeat(): array
    {
        return [
            "seat_name"      => $this->getName(),
            "seat_name_uy"   => $this->getNameUy(),
            "seat_price"     => $this->getPrice(),
            "seat_inventory" => $this->getInventory(),
            "list"           => $this->seatDetails(),
            "select_seats"   => $this->canSelectSeats(),
            "seat_type"      => $this->getSeatType(),
        ];
    }

    public function getInventory(): int
    {
        return $this->seat_inventory;
    }
}